﻿/********
* Copyright © 深圳市新元素医疗技术开发有限公司 . All rights reserved.
* 
*  Description:
*  Create By $username at $time
*  
*
*  Revision History:
*  Date                  Who                 What
*  
* 
*/

#region namespace

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Objects;
using System.Data.EntityClient;
using Cherry.Agile.Framework;
using System.Data.Common;
#endregion

namespace Cherry.Agile.Data.Repository.Extention
{
    /// <summary>
    /// 数据库查询扩展
    /// </summary>
    public static class ObjectContextExtention
    {

         #region methods

        #region public
        /// <summary>
        /// 执行T-Sql得到一个数据集。注意该方法只允许在处理复杂数据或者报表的情况下使用。
        /// </summary>
        /// <param name="context"></param>
        /// <param name="script"></param>
        /// <param name="tableNames"></param>
        /// <param name="params"></param>
        /// <returns></returns>
        [Obsolete("请使用ExcuteStoreFunction方法替代")]
        public static DataSet ExcuteDataSet(this ObjectContext context, string script,
                    string[] tableNames,params ObjectParameter[] @params)
        {
            var rd = ExcuteDataReader(context, script, CommandType.Text, @params);
            try
            {
                var ds = new DataSet();
                ds.Load(rd.Item1, LoadOption.OverwriteChanges, tableNames);
                rd.Item2.Invoke();
                return ds;
            }
            finally
            {
                rd.Item1.Close();
            }
        }

        /// <summary>
        /// 执行存储过程得到一个数据集。注意该方法只允许在处理复杂数据或者报表的情况下使用。
        /// </summary>
        /// <param name="context"></param>
        /// <param name="script"></param>
        /// <param name="tableNames"></param>
        /// <param name="params"></param>
        /// <returns></returns>
        [Obsolete("请使用ExcuteStoreFunction方法替代")]
        public static DataSet ExcuteFunction(this ObjectContext context, string script,
                string[] tableNames, params ObjectParameter[] @params)
        {
            var rd = ExcuteDataReader(context, script, CommandType.StoredProcedure, @params);
            try
            {
                var ds = new DataSet();
                ds.Load(rd.Item1, LoadOption.OverwriteChanges, tableNames);
                rd.Item2.Invoke();
                return ds;
            }
            finally
            {
                rd.Item1.Close();
            }
        }


        /// <summary>
        /// 执行存储过程获取一个结果集
        /// </summary>
        /// <param name="context"><see cref="ObjectContext"/></param>
        /// <param name="script">存储过程</param>
        /// <param name="params">参数</param>
        /// <returns>结果集</returns>
        /// <example>
        /// <code>
        /// <![CDATA[
        ///   var sp = "get_customers";
        ///   var p = new ObjectParameter("param2", ParamValue.OupoutValue<string>());//定义输出参数
        ///   using (var result = ObjectContext.ExcuteStoreFunction(sp,p ))
        ///   {
        ///       //获取结果集
        ///       var lst = result.Result<Customer>((d) =>
        ///            new Customer()
        ///               {
        ///                   CustomerID = d.GetValue<string>("CustomerID")
        ///               }
        ///   
        ///           ).ToList();
        ///   }
        ///   var count = p.Value; //获取存储过程输出参数值
        /// ]]>
        /// </code>
        /// </example>
        public static DataResult ExcuteStoreFunction(this ObjectContext context, string script, params ObjectParameter[] @params)
        {
            var rd = ExcuteDataReader(context, script, CommandType.StoredProcedure, @params);
            return new DataResult(context, rd.Item1,rd.Item2 );
        }

        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="context"><see cref="ObjectContext"/></param>
        /// <param name="script">存储过程</param>
        /// <param name="params">参数</param>
        /// <returns>结果集</returns>
        public static void ExcuteStoreFunctionNoneQuery(this ObjectContext context, string script, params ObjectParameter[] @params)
        {
            DbCommand cmd;
            Dictionary<DbParameter, ObjectParameter> outputs;
            cmd = GetCommand(context, script, CommandType.StoredProcedure, @params, out outputs);
            cmd.ExecuteNonQuery();
            cmd.Connection.Close();

            if (outputs.Count > 0)
            {
                outputs.ForEach(c =>
                {
                    c.Value.Value = c.Key.Value;
                });

            }

        }

        static Tuple<DbDataReader,Action> ExcuteDataReader(this ObjectContext context, string script,
                    CommandType cmdType, params ObjectParameter[] @params)
        {
            DbCommand cmd;
            Dictionary<DbParameter, ObjectParameter> outputs;
            cmd = GetCommand(context, script, cmdType, @params,  out outputs);

            var rd = cmd.ExecuteReader();

            return new Tuple<DbDataReader, Action>(rd, () =>
                {
                    if (outputs.Count > 0)
                    {
                        outputs.ForEach(c =>
                            {
                                c.Value.Value = c.Key.Value;
                            });

                    }
                });
        }
        

        private static DbCommand GetCommand(ObjectContext context, string script, CommandType cmdType, ObjectParameter[] @params,
            out Dictionary<DbParameter, ObjectParameter> outputs)
        {
            var con = (context.Connection as EntityConnection).StoreConnection;
            var cmd = con.CreateCommand();
            cmd.CommandType = cmdType;

            var dict = new Dictionary<DbParameter, ObjectParameter>();
            @params.ForEach(c =>
            {
                var p = cmd.CreateParameter();
                var name = c.Name;
                p.ParameterName = name;
                p.Value = c.Value;

                var val = p.Value as ParamValue;
                if (val != null)
                {
                    p.Direction = val.Direction;
                    p.Value = val.Value;
                    p.DbType = val.DbType;
                    dict.Add(p, c);
                }

                cmd.Parameters.Add(p);

            });
            outputs = dict;
            cmd.CommandText = script;
            cmd.Connection = con;
            if (con.State != ConnectionState.Open)
                con.Open();
            return cmd;
        }
 

        #endregion

        #region protected

        #endregion

        #region private

        #endregion

        #endregion


    }
}
